Skip to content

Conversation

@shubhamdhama
Copy link

@shubhamdhama shubhamdhama commented Jul 7, 2025

This change introduces support for server-side interceptors in DRPC. For a deeper understanding of interceptors, refer to the gRPC guide: https://grpc.io/docs/guides/interceptors

Although this functionality logically belongs in the drpcserver package, implementing it within drpcmux offers a more practical approach, avoiding a substantial refactor.

Fixes: cockroachdb/cockroach#147622

Copy link

@cthumuluru-crdb cthumuluru-crdb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a couple of minor comments. Otherwise the changes look good to me.


type UnaryHandler func(ctx context.Context, in interface{}) (out interface{}, err error)

type UnaryServerInterceptor func(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments and contract for the interceptors.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if currIdx == len(interceptors) {
return handler
}
return func(ctx context.Context, in interface{}) (out interface{}, err error) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about extracting this into asUnaryHandler(i UnaryInterceptor) UnaryHandler function? I find it more readable and easy to understand.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a bit more complicated. We're not just adapting the interceptor as a handler; we're also capturing arguments from getChainedUnaryHandler. This means if a method is declared as asUnaryHandler, it will still accept those arguments, making the cleanup pointless.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. I would suggest adding a comment on what that code is meant to do for future reference.

type StreamHandler func(ctx context.Context, in drpc.Stream) (out interface{}, err error)

type StreamServerInterceptor func(
ctx context.Context, stream drpc.Stream, rpc string, handler StreamHandler) (out interface{}, err error)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like we discussed before, rpc string can be replaced with StreamServerInfo similar to gRPC. Since stream interceptors apply to all forms of stream RPCs (unary request + stream response, stream request + unary response, stream request + stream response), this metadata will be useful for writing an interceptor that only applies to one form of stream interceptor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of adding this, but I'm waiting to come across any use case where we need more than an RPC string.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not necessarily suggesting to block on this but IMO interfaces should also help with future needs. I'm fine with the current approach and revisit it if needed.

@shubhamdhama shubhamdhama force-pushed the drpc/server-interceptors-fx-changes branch from 3c6288c to 5d8e4dc Compare July 8, 2025 06:43
Copy link

@cthumuluru-crdb cthumuluru-crdb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thank you!

if currIdx == len(interceptors) {
return handler
}
return func(ctx context.Context, in interface{}) (out interface{}, err error) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. I would suggest adding a comment on what that code is meant to do for future reference.

type StreamHandler func(ctx context.Context, in drpc.Stream) (out interface{}, err error)

type StreamServerInterceptor func(
ctx context.Context, stream drpc.Stream, rpc string, handler StreamHandler) (out interface{}, err error)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not necessarily suggesting to block on this but IMO interfaces should also help with future needs. I'm fine with the current approach and revisit it if needed.

This change introduces support for server-side interceptors in DRPC.
For a deeper understanding of interceptors, refer to the gRPC guide:
https://grpc.io/docs/guides/interceptors

lthough this functionality logically belongs in the `drpcserver` package,
implementing it within `drpcmux` offers a more practical approach,
avoiding a substantial refactor.
@shubhamdhama shubhamdhama force-pushed the drpc/server-interceptors-fx-changes branch from 5d8e4dc to 95e1d1c Compare July 8, 2025 08:11
@shubhamdhama shubhamdhama merged commit 293b175 into cockroachdb:main Jul 9, 2025
shubhamdhama added a commit to shubhamdhama/cockroach that referenced this pull request Jul 9, 2025
In cockroachdb/drpc#10, we added the DRPC framework level support for
interceptors. This PR ports the metrics interceptor to DRPC server.

Epic: CRDB-49359
Release note: None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

drpc: add Server interceptor support in drpc

2 participants